package edu.ucla.cs.cs144;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import org.apache.lucene.document.Field;
import org.apache.lucene.document.Document;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Hits;
import org.apache.lucene.search.Hit;
import org.apache.lucene.search.IndexSearcher;

import java.io.IOException;

import edu.ucla.cs.cs144.Columns;

public class MyIndexer 
{
    /** Creates a new instance of Indexer */
	public MyIndexer() 
	{
		indexDirectory = System.getenv("LUCENE_INDEX") + "/ebay-search";
	}
	
	public String getIndexDirectory()
	{
		return indexDirectory;
	}
	
	private String indexDirectory = "";
	private IndexWriter indexWriter = null;

	public IndexWriter getIndexWriter(boolean create) throws IOException 
	{
		if (indexWriter == null) 
		{
			indexWriter = new IndexWriter(indexDirectory,
					                   new StandardAnalyzer(),
					                   create);
		}
	
		return indexWriter;
	}    

	public void closeIndexWriter() throws IOException 
	{
		if (indexWriter != null) 
		{
			indexWriter.close();
		}
	}
	
	public void indexItemBasicSearch(ResultSet item, String categories) throws IOException, SQLException
	{
		IndexWriter writer = getIndexWriter(false);
	
		Document doc = new Document();
	
		String ItemID = item.getString(Columns.ITEMID);
		String name = item.getString(Columns.NAME);
		String description = item.getString(Columns.DESCRIPTION);
	
		doc.add(new Field(Columns.ITEMID, ItemID, Field.Store.YES, Field.Index.NO));
		doc.add(new Field(Columns.NAME, name, Field.Store.YES, Field.Index.TOKENIZED));
		doc.add(new Field(Columns.CATEGORY, categories, Field.Store.NO, Field.Index.TOKENIZED));
		doc.add(new Field(Columns.DESCRIPTION, description, Field.Store.NO, Field.Index.TOKENIZED));
		String fullSearchableText = name + " " + categories + " " + description;
		doc.add(new Field("content", fullSearchableText, Field.Store.NO, Field.Index.TOKENIZED));
		writer.addDocument(doc);
	}

	public void rebuildIndexes() 
	{
		try
		{
			//
			// Erase existing index
			//
			getIndexWriter(true);
		
			Connection conn = null;

			// create a connection to the database
			try 
			{
				conn = MyDBManager.getConnection(true);
			} 
			catch (SQLException ex) 
			{
				System.out.println(ex);
			}

			/*
			* Add your code here to retrieve Items using the connection
			* and add corresponding entries to your Lucene inverted indexes.
			*
			* You will have to use JDBC API to retrieve MySQL data from Java.
			* Read our tutorial on JDBC if you do not know how to use JDBC.
			*
			* You will also have to use Lucene IndexWriter and Document
			* classes to create an index and populate it with Items data.
			* Read our tutorial on Lucene as well if you don't know how.
			*
			* As part of this development, you may want to add 
			* new methods and create additional Java classes. 
			* If you create new classes, make sure that
			* the classes become part of "edu.ucla.cs.cs144" package
			* and place your class source files at src/edu/ucla/cs/cs144/.
			* 
			*/
		
			try
			{
				Statement statement = conn.createStatement();
				
				System.out.println("Querying items...");
				ResultSet result = statement.executeQuery("SELECT " + Columns.ITEMID + ", " + Columns.NAME + ", " + Columns.DESCRIPTION + 
															" FROM Items ORDER BY " + Columns.ITEMID);
				System.out.println("DONE");
			
				System.out.println("Creating index for items...");
				
				// get all categories and form a space delimited string
				Statement statement2 = conn.createStatement();
				ResultSet result2 = statement2.executeQuery("SELECT " + Columns.CATEGORY + ", " + Columns.ITEMID + 
															" FROM Categories, CatItems WHERE Categories." + Columns.CATEGORYID + 
															" = CatItems." + Columns.CATEGORYID + " ORDER BY " + Columns.ITEMID);
				
				HashMap<Integer, String> category_map = new HashMap<Integer, String>();
				while (result2.next()) {
					int key = result2.getInt(Columns.ITEMID);
					
					if (category_map.containsKey(key))
						category_map.put(key, category_map.get(key) + " " + result2.getString(Columns.CATEGORY));
					else
						category_map.put(key, result2.getString(Columns.CATEGORY));
				}
				
				while( result.next() )
				{	
					indexItemBasicSearch( result, category_map.get(result.getInt(Columns.ITEMID)) );
				}
				System.out.println("DONE");
			
				/* close the resultset and statement */
				result.close();
				statement.close();
				
				result2.close();
				statement2.close();
			}
			catch (SQLException ex)
			{
				System.out.println("SQLException caught");
				System.out.println("---");
				while ( ex != null )
				{
					System.out.println("Message   : " + ex.getMessage());
					System.out.println("SQLState  : " + ex.getSQLState());
					System.out.println("ErrorCode : " + ex.getErrorCode());
					System.out.println("---");
					ex = ex.getNextException();
				}
			}

			// close the database connection
			try 
			{
				conn.close();
			} 
			catch (SQLException ex) 
			{
				System.out.println(ex);
			}
		
			//
			// Don't forget to close the index writer when done
			//
			closeIndexWriter();
		}
		catch (IOException ex)
		{
			System.out.println(ex);
		}
	}    

	public static void main(String agrs[]) 
	{
		MyIndexer idx = new MyIndexer();
		idx.rebuildIndexes();
        
        /*
         *	Test code for running queries using Lucene
         */
/*
		try 
		{
			// perform search on "Notre Dame museum"
			// and retrieve the result
			System.out.println("performSearch : " + idx.getIndexDirectory());

			IndexSearcher searcher = new IndexSearcher(idx.getIndexDirectory());
			QueryParser parser = new QueryParser("content", new StandardAnalyzer());
        
			Query query = parser.parse("Collectibles");        
			Hits hits = searcher.search(query);

			System.out.println("Results found: " + hits.length());
			Iterator<Hit> iter =  hits.iterator();
			while(iter.hasNext())
			{
				Hit hit = iter.next();
				Document doc = hit.getDocument();
				System.out.println(doc.get("ItemID") + " " + "\"" + doc.get("Name") + "\"" );
			}
		
			System.out.println("performSearch done");
		} 
		catch (Exception e) 
		{
		System.out.println("Exception caught.\n");
		}
*/
	}
}
